use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::ops::Add;
use std::sync::{Arc, RwLock};
use std::thread;
use std::thread::JoinHandle;
use serde::de::Unexpected::Str;
use crate::bound::SidecarInBoundPort;
use crate::codes::http::Request;
use crate::{JaegerTracing, Response, ResponseTracing};
use crate::trace::jaeger::RequestTracing;

pub struct InBoundServer {
    listener:TcpListener,
    local_stream:TcpStream, //主容器
    trace:Option<JaegerTracing>,
}

impl InBoundServer {
    pub fn new(port:i32,trace:Option<JaegerTracing>) -> Self {
        let mut addr = String::from("0.0.0.0");
        addr.push(':');
        addr = addr.add(SidecarInBoundPort.to_string().as_str());

        let listener = TcpListener::bind(addr).unwrap();

        let mut local = String::from("127.0.0.1:");
        local = local.add(port.to_string().as_str());
        let conn = TcpStream::connect(local).unwrap();

        InBoundServer{
            listener,
            local_stream:conn,
            trace
        }
    }

    pub fn run(mut self) {
        let l = self.listener.try_clone().unwrap();

        for res in l.incoming() {
            let mut stream = res.unwrap();
            let mut local_stream = self.local_stream.try_clone().unwrap();
            let mut opt = self.trace.clone();
            match opt {
                None=> {
                    thread::spawn(move || {
                        loop {
                            let mut buf = [0;1024*10];
                            let len = stream.read(&mut buf);
                            if let Err(e) = len {
                                println!("read tcp err :{}",e.to_string());
                                break;
                            }

                            let size = len.unwrap();
                            if size == 0 {
                                continue;
                            }

                            let mut data = buf[..size].to_vec();
                            let mut rs = Request::read_from_data(data.clone());
                            if let None = rs {
                                continue;
                            }
                            let request = rs.unwrap();

                            let new_request = request.into_bytes();
                            let local_res = local_stream.write(new_request.as_slice());
                            if let Err(e) = local_res {
                                break;
                            }

                            let mut buf = [0;1024];
                            let op = local_stream.read(&mut buf);
                            if let Err(e) = op {
                                println!("{}",e);
                                break;
                            }

                            let res_data = buf[..op.unwrap()].to_vec();
                            let r = Response::from_tcp_data(res_data);
                            if let None = r {
                                continue;
                            }
                            let response = r.unwrap();
                            let op = stream.write(response.into_bytes().as_slice());
                            if let Err(e) = op {
                                break;
                            }
                        }
                    });
                }
                Some(trace) => {
                    thread::spawn(move || {
                        loop {
                            let mut buf = [0;1024*10];
                            let len = stream.read(&mut buf);
                            if let Err(e) = len {
                                println!("read tcp err :{}",e.to_string());
                                break;
                            }

                            let size = len.unwrap();
                            let mut data = buf[..size].to_vec();
                            let mut request = Request::read_from_data(data.clone()).unwrap();

                            let op = JaegerTracing::get_context_from_tcp_data(data);
                            let mut span;
                            match op {
                                Some(sc) => {
                                    span = trace.start_span(request.get_url().clone(),Some(&sc));
                                },
                                None => {
                                    span = trace.start_span(request.get_url().clone(),None);
                                }
                            }

                            request.set_http_all(&mut span);
                            let r = span.context().unwrap().inject_to_http_header(request.headers());
                            if let Err(e) = r {
                                request.set_http_error(&mut span,String::from("inject request error"));
                                trace.finish_span(span);
                                break;
                            }

                            let new_request = request.into_bytes();
                            let local_res = local_stream.write(new_request.as_slice());
                            if let Err(e) = local_res {
                                request.set_http_error(&mut span,e.to_string());
                                trace.finish_span(span);
                                break;
                            }

                            let mut buf = [0;1024*10];
                            let op = local_stream.read(&mut buf);
                            if let Err(e) = op {
                                request.set_http_error(&mut span,e.to_string());
                                trace.finish_span(span);
                                break;
                            }

                            let r = Response::from_tcp_data(buf[..op.unwrap()].to_vec());
                            if let None = r {
                                continue;
                            }
                            let response = r.unwrap();
                            response.into_span(&mut span);

                            let op = stream.write(response.into_bytes().as_slice());
                            if let Err(e) = op {
                                request.set_http_error(&mut span,e.to_string());
                                trace.finish_span(span);
                                break;
                            }

                            trace.finish_span(span);
                        }
                    });
                }
            }
        }

        // handler.join().unwrap();
    }

}